﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;
using StardewValley.Tools;

namespace WorseGame.Content
{
    public class 工具耐久(IMonitor 监视器, IModHelper 助手)
    {
        private readonly IMonitor 监视器 = 监视器;
        private readonly IModHelper 助手 = 助手;
        private readonly Dictionary<string, int> 工具耐久度 = [];
        private const int 默认耐久度 = 100;
        private Tool? 正在使用的工具 = null;
        private int 使用计时器 = 0;
        private bool 上次按键状态 = false;
        private bool 显示修复按钮 = false;
        private Rectangle 修复按钮区域;

        public void Initialize()
        {
            助手.Events.GameLoop.UpdateTicked += 更新时触发;
            助手.Events.GameLoop.DayStarted += 每日开始时;
            助手.Events.GameLoop.SaveLoaded += 存档加载时;
            助手.Events.Display.RenderedHud += 渲染界面时;
            助手.Events.Input.ButtonPressed += 按键按下时;
        }

        private void 存档加载时(object? sender, SaveLoadedEventArgs e)
        {
            加载耐久数据();
        }

        private void 每日开始时(object? sender, DayStartedEventArgs e)
        {
            初始化工具耐久度();
        }

        private void 更新时触发(object? sender, UpdateTickedEventArgs e)
        {
            显示修复按钮 = Game1.currentLocation?.Name == "Blacksmith";

            if (Context.IsWorldReady && Game1.activeClickableMenu == null && (Game1.player?.CurrentTool) != null)
            {
                var 当前工具 = Game1.player.CurrentTool;
                bool 当前按键状态 = 检测使用工具按键();
                if (当前按键状态 && !上次按键状态 && 正在使用的工具 == null)
                {
                    if (!工具已损坏(当前工具))
                    {
                        开始使用工具(当前工具);
                    }
                    else
                    {
                        Game1.playSound("cancel");
                    }
                }
                if (正在使用的工具 != null)
                {
                    使用计时器++;
                    if (检测工具使用完成(正在使用的工具, 使用计时器) || !当前按键状态)
                    {
                        结束使用工具();
                    }
                }

                上次按键状态 = 当前按键状态;
                if (工具已损坏(当前工具))
                {
                    处理工具损坏(当前工具);
                }
            }
        }

        private void 按键按下时(object? sender, ButtonPressedEventArgs e)
        {
            if (Context.IsWorldReady && Game1.activeClickableMenu == null)
            {
                if (显示修复按钮 && e.Button == SButton.MouseLeft && Game1.player.CurrentTool is Tool 当前工具 &&
                   修复按钮区域.Contains((int)e.Cursor.ScreenPixels.X, (int)e.Cursor.ScreenPixels.Y))
                {
                    铁匠铺修复工具(当前工具);
                }
            }
        }

        private static bool 检测使用工具按键()
        {
            if (Game1.activeClickableMenu == null)
            {
                return Game1.player.UsingTool;
            }

            return false;
        }

        private void 开始使用工具(Tool 工具)
        {
            正在使用的工具 = 工具;
            使用计时器 = 0;
        }

        private void 结束使用工具()
        {
            if (正在使用的工具 != null)
            {
                消耗耐久度(正在使用的工具);
            }

            正在使用的工具 = null;
            使用计时器 = 0;
        }

        private static bool 检测工具使用完成(Tool 工具, int 计时器)
        {
            return 工具 switch
            {
                Axe or Pickaxe => 计时器 > 30,
                Hoe => 计时器 > 10,
                WateringCan => 计时器 > 45,
                FishingRod 鱼竿 => 鱼竿.isFishing && 鱼竿.hit,
                MeleeWeapon => 计时器 > 15,               
                _ => 计时器 > 20
            };
        }

        private void 渲染界面时(object? sender, RenderedHudEventArgs e)
        {
            if (!Context.IsWorldReady || Game1.activeClickableMenu != null)
                return;

            显示工具耐久度提示(e.SpriteBatch);
        }

        private void 显示工具耐久度提示(SpriteBatch spriteBatch)
        {
            if (Game1.player.CurrentTool is Tool 当前工具)
            {
                int 耐久度 = 获取工具耐久度(当前工具);
                float 耐久度百分比 = 获取工具耐久度百分比(当前工具);
                int 提示宽度 = 180;
                int 提示高度 = 110;
                int 右边距 = 20;
                int 下边距 = 300;
                int 提示X = Game1.viewport.Width - 提示宽度 - 右边距;
                int 提示Y = Game1.viewport.Height - 提示高度 - 下边距;
                IClickableMenu.drawTextureBox(spriteBatch, Game1.menuTexture, new Rectangle(0, 256, 60, 60),
                    提示X, 提示Y, 提示宽度, 提示高度, Color.White);
                string 工具名称 = 当前工具.DisplayName;
                Vector2 名称尺寸 = Game1.smallFont.MeasureString(工具名称);
                Vector2 名称位置 = new(提示X + (提示宽度 - 名称尺寸.X) / 2, 提示Y + 12);
                Utility.drawTextWithShadow(spriteBatch, 工具名称, Game1.smallFont, 名称位置, Game1.textColor);
                string 耐久度文本 = $"耐久度: {耐久度}/{默认耐久度}";
                Vector2 耐久度位置 = new(提示X + 15, 提示Y + 30);
                Color 耐久度颜色 = 耐久度百分比 switch
                {
                    > 0.7f => Color.LightGreen,
                    > 0.3f => Color.Yellow,
                    > 0f => Color.Orange,
                    _ => Color.Red
                };
                Utility.drawTextWithShadow(spriteBatch, 耐久度文本, Game1.smallFont, 耐久度位置, 耐久度颜色);
                int 进度条Y = 提示Y + 60;
                绘制耐久度进度条(spriteBatch, 提示X + 15, 进度条Y, 提示宽度 - 30, 12, 耐久度百分比);
                int 状态提示Y = 提示Y + 70;
                if (工具需要修复(当前工具))
                {
                    string 状态提示 = "需要修复";
                    Vector2 状态提示位置 = new(提示X + 15, 状态提示Y);
                    Utility.drawTextWithShadow(spriteBatch, 状态提示, Game1.smallFont, 状态提示位置, Color.Orange);
                }
                else
                {
                    string 状态提示 = "状态良好";
                    Vector2 状态提示位置 = new(提示X + 15, 状态提示Y);
                    Utility.drawTextWithShadow(spriteBatch, 状态提示, Game1.smallFont, 状态提示位置, Color.LightGreen);
                }
                if (显示修复按钮 && 工具需要修复(当前工具))
                {
                    int 修复费用 = 计算修复费用(当前工具);
                    int 按钮Y = 提示Y + 140;
                    修复按钮区域 = new Rectangle(提示X + 15, 按钮Y, 提示宽度 - 30, 25);
                    Color 按钮颜色 = 修复按钮区域.Contains(Game1.getMouseX(), Game1.getMouseY()) ? Color.Wheat : Color.White;
                    IClickableMenu.drawTextureBox(spriteBatch, Game1.menuTexture, new Rectangle(0, 256, 60, 60), 修复按钮区域.X, 修复按钮区域.Y, 修复按钮区域.Width, 修复按钮区域.Height, 按钮颜色);
                    string 按钮文字 = $"修复工具 ({修复费用}g)";
                    Vector2 文字尺寸 = Game1.smallFont.MeasureString(按钮文字);
                    Vector2 文字位置 = new Vector2(
                        修复按钮区域.X + (修复按钮区域.Width - 文字尺寸.X) / 2,
                        修复按钮区域.Y + (修复按钮区域.Height - 文字尺寸.Y) / 2
                    );
                    Color 文字颜色 = Game1.player.Money >= 修复费用 ? Color.Black : Color.Gray;
                    Utility.drawTextWithShadow(spriteBatch, 按钮文字, Game1.smallFont, 文字位置, 文字颜色);
                }
            }
        }

        private static void 绘制耐久度进度条(SpriteBatch spriteBatch, int x, int y, int width, int height, float 进度)
        {
            Color 背景颜色 = new(60, 60, 60, 200);
            spriteBatch.Draw(Game1.staminaRect, new Rectangle(x, y, width, height), 背景颜色);
            Color 进度颜色 = 进度 switch
            {
                > 0.7f => new Color(100, 200, 100, 255),
                > 0.3f => new Color(255, 200, 50, 255),
                > 0f => new Color(255, 120, 50, 255),
                _ => new Color(220, 80, 80, 255)
            };

            int 进度宽度 = (int)(width * 进度);
            if (进度宽度 > 0)
            {
                spriteBatch.Draw(Game1.staminaRect, new Rectangle(x, y, 进度宽度, height), 进度颜色);
            }
            Color 边框颜色 = new Color(40, 40, 40, 255);
            spriteBatch.Draw(Game1.staminaRect, new Rectangle(x, y, width, 1), 边框颜色);
            spriteBatch.Draw(Game1.staminaRect, new Rectangle(x, y + height - 1, width, 1), 边框颜色);
            spriteBatch.Draw(Game1.staminaRect, new Rectangle(x, y, 1, height), 边框颜色);
            spriteBatch.Draw(Game1.staminaRect, new Rectangle(x + width - 1, y, 1, height), 边框颜色);
        }

        private void 消耗耐久度(Tool 工具)
        {
            if (工具 is not FishingRod 鱼竿 || 鱼竿.hit)
            {
                string 工具标识 = 获取工具标识(工具);

                if (!工具耐久度.ContainsKey(工具标识))
                {
                    工具耐久度[工具标识] = 默认耐久度;
                }

                int 消耗量 = 计算耐久消耗量(工具);
                工具耐久度[工具标识] -= 消耗量;               
                保存耐久数据();
            }
        }

        private static int 计算耐久消耗量(Tool 工具)
        {
            return 工具 switch
            {
                Axe => 2,
                Pickaxe => 2,
                Hoe => 1,
                WateringCan => 1,
                FishingRod => 3,
                MilkPail => 1,
                Shears => 1,
                MeleeWeapon => 2,
                _ => 1
            };
        }

        private bool 工具已损坏(Tool 工具)
        {
            string 工具标识 = 获取工具标识(工具);
            return 工具耐久度.ContainsKey(工具标识) && 工具耐久度[工具标识] <= 0;
        }

        private void 处理工具损坏(Tool 工具)
        {
            Game1.playSound("breakingGlass");
            if (Game1.player.CurrentTool == 工具)
            {
                切换到可用工具();
            }
        }

        private void 切换到可用工具()
        {
            for (int i = 0; i < Game1.player.Items.Count; i++)
            {
                if (Game1.player.Items[i] is Tool 其他工具 && !工具已损坏(其他工具))
                {
                    Game1.player.CurrentToolIndex = i;
                    return;
                }
            }
            Game1.player.CurrentTool = null;
        }

        private void 初始化工具耐久度()
        {
            foreach (var 物品 in Game1.player.Items)
            {
                if (物品 is Tool 工具)
                {
                    string 工具标识 = 获取工具标识(工具);
                    if (!工具耐久度.ContainsKey(工具标识))
                    {
                        工具耐久度[工具标识] = 默认耐久度;
                    }
                }
            }
            保存耐久数据();
        }

        public bool 铁匠铺修复工具(Tool 工具)
        {
            if (!工具需要修复(工具))
            {
                return false;
            }

            int 修复费用 = 计算修复费用(工具);

            if (Game1.player.Money >= 修复费用)
            {
                Game1.player.Money -= 修复费用;
                完全修复工具(工具);
                Game1.playSound("coin");           
                return true;
            }
            else
            {
                return false;
            }
        }

        private void 完全修复工具(Tool 工具)
        {
            string 工具标识 = 获取工具标识(工具);

            if (工具耐久度.ContainsKey(工具标识))
            {
                工具耐久度[工具标识] = 默认耐久度;
                保存耐久数据();
            }
        }

        private int 计算修复费用(Tool 工具)
        {
            int 缺失耐久度 = 默认耐久度 - 获取工具耐久度(工具);
            int 基础费用 = 缺失耐久度 * 2;
            int 升级倍率 = 工具.UpgradeLevel + 1;

            return 基础费用 * 升级倍率;
        }

        public bool 工具需要修复(Tool 工具)
        {
            return 获取工具耐久度(工具) < 默认耐久度;
        }

        public int 获取工具耐久度(Tool 工具)
        {
            string 工具标识 = 获取工具标识(工具);
            return 工具耐久度.TryGetValue(工具标识, out int value) ? value : 默认耐久度;
        }

        public float 获取工具耐久度百分比(Tool 工具)
        {
            int 当前耐久度 = 获取工具耐久度(工具);
            return (float)当前耐久度 / 默认耐久度;
        }

        private static string 获取工具标识(Tool 工具)
        {
            return $"{工具.GetType().Name}_{工具.UpgradeLevel}_{工具.InitialParentTileIndex}";
        }

        private void 加载耐久数据()
        {
            string? 耐久数据 = 助手.Data.ReadSaveData<string>("ToolDurabilityData");
            if (!string.IsNullOrEmpty(耐久数据))
            {
                工具耐久度.Clear();
                var 数据数组 = 耐久数据.Split(';');
                foreach (var 数据项 in 数据数组)
                {
                    if (!string.IsNullOrEmpty(数据项))
                    {
                        var 键值对 = 数据项.Split(':');
                        if (键值对.Length == 2)
                        {
                            工具耐久度[键值对[0]] = int.Parse(键值对[1]);
                        }
                    }
                }
            }
        }

        private void 保存耐久数据()
        {
            List<string> 数据列表 = [];
            foreach (var 耐久项 in 工具耐久度)
            {
                数据列表.Add($"{耐久项.Key}:{耐久项.Value}");
            }
            string 耐久数据 = string.Join(";", 数据列表);
            助手.Data.WriteSaveData("ToolDurabilityData", 耐久数据);
        }
    }
}